﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Reflection;

namespace Light.Utility
{

    /// <summary>
    /// JSON数据转换器
    /// </summary>
    public class JsonConverter
    {

        /// <summary>
        /// 将DataTable转换成JSON数据
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static string DataTableToJson(DataTable dt)
        {

            if (dt == null || dt.Rows.Count == 0) return string.Empty;

            //[{"name":"abc","age":"23"},{"name":"bcd","age":"25"}]
            StringBuilder builder = new StringBuilder();

            builder.Append("[");

            int cntRow = dt.Rows.Count;
            int cntCol = dt.Columns.Count;

            for (int i = 0; i < cntRow; i++)
            {
                builder.Append("{");
                for (int j = 0; j < cntCol; j++)
                {
                    builder.Append("\"" + dt.Columns[j].ColumnName + "\"");
                    builder.Append(":");
                    if (dt.Rows[i][j] != null)
                    {
                        builder.Append("\"" + String2Json(dt.Rows[i][j]) + "\"");
                    }
                    else
                    {
                        builder.Append("\" \"");
                    }
                    builder.Append(",");
                }
                builder.Remove(builder.Length - 1, 1);
                builder.Append("}");
                builder.Append(",");
            }

            builder.Remove(builder.Length - 1, 1);
            builder.Append("]");

            return builder.ToString();

        }

        /// <summary>
        /// 将对象转换成JSON数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj">需要json化的对象实例,json化所有可json化的属性</param>
        /// <returns></returns>
        public static string ObjectToJson<T>(IEnumerable<T> objs)
        {
            return ObjectToJson<T>(objs, null);
        }

        /// <summary>
        /// 将对象集合转换成JSON数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="objs">需要json化的对象实例</param>
        /// <param name="properties">需要json化的属性名集合，为null时表示json化所有可json化的属性</param>
        /// <returns></returns>
        public static string ObjectToJson<T>(IEnumerable<T> objs, IList<string> properties)
        {
            if (objs == null || objs.Count() == 0) return string.Empty;

            if (properties == null || properties.Count == 0)
                properties = ReflectionHelper.GetProperties<T>();

            StringBuilder builder = new StringBuilder("[");
            foreach (var obj in objs)
            {
                builder.Append(ObjectToJson<T>(obj, properties));
                builder.Append(",");
            }
            if (objs.Count() > 0)
            {
                builder.Remove(builder.Length - 1, 1);
            }
            builder.Append("]");
            return builder.ToString();

        }

        /// <summary>
        /// 将对象转换成JSON数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="objs">需要json化的对象实例</param>
        /// <param name="properties">需要json化的属性名集合，为null时表示json化所有可json化的属性</param>
        /// <returns></returns>
        public static string ObjectToJson<T>(T obj, IList<string> properties)
        {
            if (properties == null || properties.Count == 0)
                properties = ReflectionHelper.GetProperties<T>();

            StringBuilder builder = new StringBuilder();

            builder.Append("{");
            foreach (var property in properties)
            {
                string key = property;

                //忽略不进行JSON序列化的属性
                if (ReflectionHelper.HasAttribute<T, NonJsonSerializeAttribute>(property))
                    continue;
                if (ReflectionHelper.HasAttribute<T, JsonSerializeAttribute>(property))
                {
                    string ignore = ReflectionHelper.GetPropertyAttribute<T, JsonSerializeAttribute>(property, "IgnoreMobile");
                    if (Boolean.Parse(ignore) && WebHelper.IsMobileDevice())
                        continue;
                    string cKey = ReflectionHelper.GetPropertyAttribute<T, JsonSerializeAttribute>(property, "Key");
                    key = !String.IsNullOrEmpty(cKey) ? cKey : key;
                }
                object value = ReflectionHelper.GetPropertyValue(obj, property);


                builder.Append("\"" + key + "\"");
                builder.Append(":");
                builder.Append("\"" + String2Json(value) + "\"");
                builder.Append(",");

                if (value is Enum)
                {
                    builder.Append("\"" + key + "Value\"");
                    builder.Append(":");
                    builder.Append("\"" + Convert.ToInt32(value) + "\"");
                    builder.Append(",");
                }

            }
            builder.Remove(builder.Length - 1, 1);
            builder.Append("}");

            return builder.ToString();
        }

        /// <summary>
        /// 将对象转换成JSON数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj">需要json化的对象实例,json化所有可json化的属性</param>
        /// <returns></returns>
        public static string ObjectToJson<T>(T obj)
        {
            return ObjectToJson<T>(obj, null);
        }

        private static string String2Json(object obj)
        {
            if (obj == null)
                return string.Empty;

            string s = obj.ToString();

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < s.Length; i++)
            {
                char c = s.ToCharArray()[i];
                switch (c)
                {
                    case '\"':
                        sb.Append("\\\""); break;
                    case '\\':
                        sb.Append("\\\\"); break;
                    case '/':
                        sb.Append("\\/"); break;
                    case '\b':
                        sb.Append("\\b"); break;
                    case '\f':
                        sb.Append("\\f"); break;
                    case '\n':
                        sb.Append("\\n"); break;
                    case '\r':
                        sb.Append("\\r"); break;
                    case '\t':
                        sb.Append("\\t"); break;
                    default:
                        sb.Append(c); break;
                }
            }
            return sb.ToString();
        }
    }
}
